using System;
using System.Diagnostics;
using Community.CsharpSqlite.Entity;

namespace Community.CsharpSqlite
{
    using sqlite3_uint64 = UInt64;
    /// <summary>
    ///  Memory allocation functions used throughout sqlite.
    /// </summary>
    public class Malloc
    {
        /*
    ** 2001 September 15
    **
    ** The author disclaims copyright to this source code.  In place of
    ** a legal notice, here is a blessing:
    **
    **    May you do good and not evil.
    **    May you find forgiveness for yourself and forgive others.
    **    May you share freely, never taking more than you give.
    **
    *************************************************************************
    **
    ** Memory allocation functions used throughout sqlite.
    *************************************************************************
    **  Included in SQLite3 port to C#-SQLite;  2008 Noah B Hart
    **  C#-SQLite is an independent reimplementation of the SQLite software library
    **
    **  SQLITE_SOURCE_ID: 2009-12-07 16:39:13 1ed88e9d01e9eda5cbc622e7614277f29bcc551c
    **
    **  $Header: Community.CsharpSqlite/src/malloc_c.cs,v 36ea17db6ba3 2010/02/22 16:26:59 Noah $
    *************************************************************************
    */
        //#include "sqliteInt.h"
        //#include <stdarg.h>

        /*
    ** This routine runs when the memory allocator sees that the
    ** total memory allocation is about to exceed the soft heap
    ** limit.
    */

        private static void softHeapLimitEnforcer(
            object NotUsed,
            long NotUsed2,
            int allocSize
            )
        {
            Helper.UNUSED_PARAMETER2(NotUsed, NotUsed2);
            sqlite3_release_memory(allocSize);
        }

        /*
    ** Set the soft heap-size limit for the library. Passing a zero or 
    ** negative value indicates no limit.
    */

        private void sqlite3_soft_heap_limit(int n)
        {
            int iLimit;
            int overage;
            if (n < 0)
            {
                iLimit = 0;
            }
            else
            {
                iLimit = n;
            }
#if !SQLITE_OMIT_AUTOINIT
            Sqlite3.sqlite3_initialize();
#endif
            if (iLimit > 0)
            {
                MemoryAlarm(softHeapLimitEnforcer, 0, iLimit);
            }
            else
            {
                MemoryAlarm(null, null, 0);
            }
            overage = (int)(sqlite3_memory_used() - n);
            if (overage > 0)
            {
                sqlite3_release_memory(overage);
            }
        }

        /*
    ** Attempt to release up to n bytes of non-essential memory currently
    ** held by SQLite. An example of non-essential memory is memory used to
    ** cache database pages that are not currently in use.
    */

        private static int sqlite3_release_memory(int n)
        {
#if SQLITE_ENABLE_MEMORY_MANAGEMENT
  int nRet = 0;
  nRet += sqlite3PcacheReleaseMemory(n-nRet);
  return nRet;
#else
            Helper.UNUSED_PARAMETER(n);
            return StatusCode.SQLITE_OK;
#endif
        }


        /*
    ** Initialize the memory allocation subsystem.
    */

        public static int MallocInit()
        {
            if (Global.Config.m.xMalloc == null)
            {
                MemPool.MemSetDefault();
            }
            Global.mem0 = new Mem0Global(0, 0, null, 0, null, null, 1, 1, 8, 8); //memset(&Global.mem0, 0, sizeof(Global.mem0));
            if (Global.Config.bCoreMutex)
            {
                Global.mem0.mutex = MutexHelper.MutexAlloc(MutexType.SQLITE_MUTEX_STATIC_MEM);
            }
            if (Global.Config.pScratch != null && Global.Config.szScratch >= 100
                && Global.Config.nScratch >= 0)
            {
                int i;
                Global.Config.szScratch = Utility.ROUNDDOWN8(Global.Config.szScratch - 4);
                //Global.mem0.aScratchFree = (uint*)&((char*)Global.Config.pScratch)
                //  [Global.Config.szScratch*Global.Config.nScratch];
                //for(i=0; i<Global.Config.nScratch; i++){ Global.mem0.aScratchFree[i] = i; }
                //Global.mem0.nScratchFree = Global.Config.nScratch;
            }
            else
            {
                Global.Config.pScratch = null;
                Global.Config.szScratch = 0;
            }
            if (Global.Config.pPage != null && Global.Config.szPage >= 512
                && Global.Config.nPage >= 1)
            {
                int i;
                int overhead;
                int sz = Utility.ROUNDDOWN8(Global.Config.szPage);
                int n = Global.Config.nPage;
                overhead = (4 * n + sz - 1) / sz;
                Global.Config.nPage -= overhead;
                //Global.mem0.aPageFree = (uint*)&((char*)Global.Config.pPage)
                //[Global.Config.szPage*Global.Config.nPage];
                //for(i=0; i<Global.Config.nPage; i++){ Global.mem0.aPageFree[i] = i; }
                //Global.mem0.nPageFree = Global.Config.nPage;
            }
            else
            {
                Global.Config.pPage = null;
                Global.Config.nPage = 0;
            }
            return Global.Config.m.xInit(Global.Config.m.pAppData);
        }

        /*
    ** Deinitialize the memory allocation subsystem.
    */

        public static void MallocEnd()
        {
            if (Global.Config.m.xShutdown != null)
            {
                Global.Config.m.xShutdown(Global.Config.m.pAppData);
            }
            Global.mem0 = new Mem0Global(); //memset(&Global.mem0, 0, sizeof(Global.mem0));
        }

        /*
    ** Return the amount of memory currently checked out.
    */

        private static long sqlite3_memory_used()
        {
            int n = 0, mx = 0;
            long res;
            StatusHelper.GetStatus(SqliteStatus.SQLITE_STATUS_MEMORY_USED, ref n, ref mx, 0);
            res = n; /* Work around bug in Borland C. Ticket #3216 */
            return res;
        }

        /*
    ** Return the maximum amount of memory that has ever been
    ** checked out since either the beginning of this process
    ** or since the most recent reset.
    */

        private static long sqlite3_memory_highwater(int resetFlag)
        {
            int n = 0, mx = 0;
            long res;
            StatusHelper.GetStatus(SqliteStatus.SQLITE_STATUS_MEMORY_USED, ref n, ref mx, resetFlag);
            res = mx; /* Work around bug in Borland C. Ticket #3216 */
            return res;
        }

        /*
    ** Change the alarm callback
    */

        private static int MemoryAlarm(
            dxalarmCallback xCallback, //void(*xCallback)(void pArg, long used,int N),
            object pArg,
            long iThreshold
            )
        {
            MutexHelper.MutexEnter(Global.mem0.mutex);
            Global.mem0.alarmCallback = xCallback;
            Global.mem0.alarmArg = pArg;
            Global.mem0.alarmThreshold = iThreshold;
            MutexHelper.MutexLeave(Global.mem0.mutex);
            return StatusCode.SQLITE_OK;
        }

        /*
    ** Trigger the alarm 
    */

        private static void MallocAlarm(int nByte)
        {
            dxalarmCallback xCallback; //void (*xCallback)(void*,long,int);
            long nowUsed;
            object pArg; // void* pArg;
            if (Global.mem0.alarmCallback == null) return;
            xCallback = Global.mem0.alarmCallback;
            nowUsed = StatusHelper.StatusValue(SqliteStatus.SQLITE_STATUS_MEMORY_USED);
            pArg = Global.mem0.alarmArg;
            Global.mem0.alarmCallback = null;
            MutexHelper.MutexLeave(Global.mem0.mutex);
            xCallback(pArg, nowUsed, nByte);
            MutexHelper.MutexEnter(Global.mem0.mutex);
            Global.mem0.alarmCallback = xCallback;
            Global.mem0.alarmArg = pArg;
        }

        /*
    ** Do a memory allocation with statistics and alarms.  Assume the
    ** lock is already held.
    */

        private static int mallocWithAlarm(int n, ref int[] pp)
        {
            int nFull;
            int[] p;
            Debug.Assert(MutexHelper.MutexHeld(Global.mem0.mutex));
            nFull = Global.Config.m.xRoundup(n);
            StatusHelper.StatusSet(SqliteStatus.SQLITE_STATUS_MALLOC_SIZE, n);
            if (Global.mem0.alarmCallback != null)
            {
                int nUsed = StatusHelper.StatusValue(SqliteStatus.SQLITE_STATUS_MEMORY_USED);
                if (nUsed + nFull >= Global.mem0.alarmThreshold)
                {
                    MallocAlarm(nFull);
                }
            }
            p = Global.Config.m.xMallocInt(nFull);
            //if( p==null && Global.mem0.alarmCallback!=null ){
            //  sqlite3MallocAlarm(nFull);
            //  p = Global.Config.m.xMalloc(nFull);
            //}
            if (p != null)
            {
                nFull = MallocSize(p);
                StatusHelper.StatusAdd(SqliteStatus.SQLITE_STATUS_MEMORY_USED, nFull);
            }
            pp = p;
            return nFull;
        }

        private static int mallocWithAlarm(int n, ref byte[] pp)
        {
            int nFull;
            byte[] p;
            Debug.Assert(MutexHelper.MutexHeld(Global.mem0.mutex));
            nFull = Global.Config.m.xRoundup(n);
            StatusHelper.StatusSet(SqliteStatus.SQLITE_STATUS_MALLOC_SIZE, n);
            if (Global.mem0.alarmCallback != null)
            {
                int nUsed = StatusHelper.StatusValue(SqliteStatus.SQLITE_STATUS_MEMORY_USED);
                if (nUsed + nFull >= Global.mem0.alarmThreshold)
                {
                    MallocAlarm(nFull);
                }
            }
            p = Global.Config.m.xMalloc(nFull);
            if (p == null && Global.mem0.alarmCallback != null)
            {
                MallocAlarm(nFull);
                p = Global.Config.m.xMalloc(nFull);
            }
            if (p != null)
            {
                nFull = MallocSize(p);
                StatusHelper.StatusAdd(SqliteStatus.SQLITE_STATUS_MEMORY_USED, nFull);
            }
            pp = p;
            return nFull;
        }

        /*
    ** Allocate memory.  This routine is like sqlite3_malloc() except that it
    ** assumes the memory subsystem has already been initialized.
    */

        public static Mem sqlite3Malloc(Mem pMem)
        {
            return Global.Config.m.xMallocMem(pMem);
        }

        public static int[] sqlite3Malloc(int[] pInt, int n)
        {
            int[] p = null;
            if (n < 0 || n >= 0x7fffff00)
            {
                /* A memory allocation of a number of bytes which is near the maximum
        ** signed integer value might cause an integer overflow inside of the
        ** xMalloc().  Hence we limit the maximum size to 0x7fffff00, giving
        ** 255 bytes of overhead.  SQLite itself will never use anything near
        ** this amount.  The only way to reach the limit is with sqlite3_malloc() */
                p = null;
            }
            else if (Global.Config.bMemstat)
            {
                MutexHelper.MutexEnter(Global.mem0.mutex);
                mallocWithAlarm(n, ref p);
                MutexHelper.MutexLeave(Global.mem0.mutex);
            }
            else
            {
                p = Global.Config.m.xMallocInt(n);
            }
            return p;
        }

        public static byte[] sqlite3Malloc(int n)
        {
            byte[] p = null;
            if (n < 0 || n >= 0x7fffff00)
            {
                /* A memory allocation of a number of bytes which is near the maximum
        ** signed integer value might cause an integer overflow inside of the
        ** xMalloc().  Hence we limit the maximum size to 0x7fffff00, giving
        ** 255 bytes of overhead.  SQLite itself will never use anything near
        ** this amount.  The only way to reach the limit is with sqlite3_malloc() */
                p = null;
            }
            else if (Global.Config.bMemstat)
            {
                MutexHelper.MutexEnter(Global.mem0.mutex);
                mallocWithAlarm(n, ref p);
                MutexHelper.MutexLeave(Global.mem0.mutex);
            }
            else
            {
                p = Global.Config.m.xMalloc(n);
            }
            return p;
        }

        /*
    ** This version of the memory allocation is for use by the application.
    ** First make sure the memory subsystem is initialized, then do the
    ** allocation.
    */

        public static byte[] sqlite3_malloc(int n)
        {
#if !SQLITE_OMIT_AUTOINIT
            if (Sqlite3.sqlite3_initialize() != 0) return null;
#endif
            return sqlite3Malloc(n);
        }

        /*
    ** Each thread may only have a single outstanding allocation from
    ** xScratchMalloc().  We verify this constraint in the single-threaded
    ** case by setting scratchAllocOut to 1 when an allocation
    ** is outstanding clearing it when the allocation is freed.
    */
#if SQLITE_THREADSAFE && !(NDEBUG)
static int scratchAllocOut = 0;
#endif


        /*
** Allocate memory that is to be used and released right away.
** This routine is similar to alloca() in that it is not intended
** for situations where the memory might be held long-term.  This
** routine is intended to get memory to old large transient data
** structures that would not normally fit on the stack of an
** embedded processor.
*/

        public static byte[][] ScratchMalloc(byte[][] apCell, int n)
        {
            apCell = Global.Config.pScratch2;
            if (apCell == null) apCell = new byte[n < 200 ? 200 : n][];
            else if (apCell.Length < n) Array.Resize(ref apCell, n);
            Global.Config.pScratch2 = null;
            return apCell;
        }

        public static byte[] ScratchMalloc(int n)
        {
            byte[] p = null;
            Debug.Assert(n > 0);

#if SQLITE_THREADSAFE && !(NDEBUG)
    /* Verify that no more than one scratch allocation per thread
  ** is outstanding at one time.  (This is only checked in the
  ** single-threaded case since checking in the multi-threaded case
  ** would be much more complicated.) */
  assert( scratchAllocOut==0 );
#endif

            if (Global.Config.szScratch < n)
            {
                goto scratch_overflow;
            }
            else
            {
                MutexHelper.MutexEnter(Global.mem0.mutex);
                if (Global.mem0.nScratchFree == 0)
                {
                    MutexHelper.MutexLeave(Global.mem0.mutex);
                    goto scratch_overflow;
                }
                else
                {
                    int i;
                    //i = Global.mem0.aScratchFree[--Global.mem0.nScratchFree];
                    //i *= Global.Config.szScratch;
                    for (i = 0; i < Global.Config.pScratch.Length; i++)
                    {
                        if (Global.Config.pScratch[i] == null || Global.Config.pScratch[i].Length < n)
                            continue;
                        p = Global.Config.pScratch[i]; // (void*)&((char*)Global.Config.pScratch)[i];
                        Global.Config.pScratch[i] = null;
                        break;
                    }
                    MutexHelper.MutexLeave(Global.mem0.mutex);
                    if (p == null) goto scratch_overflow;
                    StatusHelper.StatusAdd(SqliteStatus.SQLITE_STATUS_SCRATCH_USED, 1);
                    StatusHelper.StatusSet(SqliteStatus.SQLITE_STATUS_SCRATCH_SIZE, n);
                    //assert(  (((byte*)p - (byte*)0) & 7)==0 );
                }
            }
#if SQLITE_THREADSAFE && !(NDEBUG)
  scratchAllocOut = p!=0;
#endif

            return p;

        scratch_overflow:
            if (Global.Config.bMemstat)
            {
                MutexHelper.MutexEnter(Global.mem0.mutex);
                StatusHelper.StatusSet(SqliteStatus.SQLITE_STATUS_SCRATCH_SIZE, n);
                n = mallocWithAlarm(n, ref p);
                if (p != null) StatusHelper.StatusAdd(SqliteStatus.SQLITE_STATUS_SCRATCH_OVERFLOW, n);
                MutexHelper.MutexLeave(Global.mem0.mutex);
            }
            else
            {
                p = Global.Config.m.xMalloc(n);
            }
#if SQLITE_THREADSAFE && !(NDEBUG)
  scratchAllocOut = p!=0;
#endif
            return p;
        }

        public static void ScratchFree(byte[][] p)
        {
            if (p != null)
            {
#if SQLITE_THREADSAFE && !(NDEBUG)
    /* Verify that no more than one scratch allocation per thread
    ** is outstanding at one time.  (This is only checked in the
    ** single-threaded case since checking in the multi-threaded case
    ** would be much more complicated.) */
    assert( scratchAllocOut==1 );
    scratchAllocOut = 0;
#endif

                if (Global.Config.pScratch2 == null || Global.Config.pScratch2.Length < p.Length)
                {
                    if (Global.Config.bMemstat)
                    {
                        int iSize = MallocSize(p);
                        MutexHelper.MutexEnter(Global.mem0.mutex);
                        StatusHelper.StatusAdd(SqliteStatus.SQLITE_STATUS_SCRATCH_OVERFLOW, -iSize);
                        StatusHelper.StatusAdd(SqliteStatus.SQLITE_STATUS_MEMORY_USED, -iSize);
                        Global.Config.pScratch2 = p; // Global.Config.m.xFree(ref p);
                        MutexHelper.MutexLeave(Global.mem0.mutex);
                    }
                    else
                    {
                        Global.Config.pScratch2 = p; //Global.Config.m.xFree(ref p);
                    }
                }
                else // larger Scratch 2 already in use, let the C# GC handle
                {
                    //int i;
                    //i = (int)((byte*)p - (byte*)Global.Config.pScratch);
                    //i /= Global.Config.szScratch;
                    //Debug.Assert(i >= 0 && i < Global.Config.nScratch);
                    //MutexHelper.MutexEnter(Global.mem0.mutex);
                    //Debug.Assert(Global.mem0.nScratchFree < (uint)Global.Config.nScratch);
                    //Global.mem0.aScratchFree[Global.mem0.nScratchFree++] = i;
                    //StatusHelper.StatusAdd(SqliteStatus.SQLITE_STATUS_SCRATCH_USED, -1);
                    //MutexHelper.MutexLeave(Global.mem0.mutex);
                }
                p = null;
            }
        }

        /*
    ** TRUE if p is a lookaside memory allocation from db
    */
#if !SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlite3 *db, void *p){
  return db && p && p>=db->lookaside.pStart && p<db->lookaside.pEnd;
}
#else
        //#define isLookaside(A,B) 0
        private static bool isLookaside(sqlite3 db, object p)
        {
            return false;
        }
#endif

        /*
** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc().
*/

        public static int MallocSize(byte[][] p)
        {
            return p.Length * p[0].Length;
        }

        public static int MallocSize(int[] p)
        {
            return p.Length;
        }

        public static int MallocSize(byte[] p)
        {
            return Global.Config.m.xSize(p);
        }

        private static int sqlite3DbMallocSize(sqlite3 db, byte[] p)
        {
            Debug.Assert(db == null || MutexHelper.MutexHeld(db.mutex));
            if (isLookaside(db, p))
            {
                return db.lookaside.sz;
            }
            else
            {
                return Global.Config.m.xSize(p);
            }
        }

        /*
    ** Free memory previously obtained from sqlite3Malloc().
    */

        public static void sqlite3_free(ref byte[] p)
        {
            if (p == null) return;
            if (Global.Config.bMemstat)
            {
                MutexHelper.MutexEnter(Global.mem0.mutex);
                StatusHelper.StatusAdd(SqliteStatus.SQLITE_STATUS_MEMORY_USED, -MallocSize(p));
                Global.Config.m.xFree(ref p);
                MutexHelper.MutexLeave(Global.mem0.mutex);
            }
            else
            {
                Global.Config.m.xFree(ref p);
            }
            p = null;
        }

        public static void sqlite3_free(ref Mem p)
        {
            if (p == null) return;
            if (Global.Config.bMemstat)
            {
                MutexHelper.MutexEnter(Global.mem0.mutex);
                //StatusHelper.StatusAdd( SqliteStatus.SQLITE_STATUS_MEMORY_USED, -Malloc.MallocSize( p ) );
                Global.Config.m.xFreeMem(ref p);
                MutexHelper.MutexLeave(Global.mem0.mutex);
            }
            else
            {
                Global.Config.m.xFreeMem(ref p);
            }
            p = null;
        }

        /*
    ** Free memory that might be associated with a particular database
    ** connection.
    */

        private static void DbFree(sqlite3 db, ref byte[] p)
        {
            Debug.Assert(db == null || MutexHelper.MutexHeld(db.mutex));
#if !SQLITE_OMIT_LOOKASIDE
  if( isLookaside(db, p) ){
  LookasideSlot *pBuf = (LookasideSlot*)p;
    pBuf.pNext = db.lookaside.pFree;
    db.lookaside.pFree = pBuf;
    db.lookaside.nOut--;
  }else
#endif
            {
                sqlite3_free(ref p);
            }
        }

        /*
    ** Change the size of an existing memory allocation
    */

        private static byte[] sqlite3Realloc(byte[] pOld, int nBytes)
        {
            int nOld, nNew;
            byte[] pNew;
            if (pOld == null)
            {
                pOld = sqlite3Malloc(nBytes);
                return pOld;
            }
            if (nBytes < 0)
            {
                sqlite3_free(ref pOld);
                return null;
            }
            if (nBytes >= 0x7fffff00)
            {
                /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */
                return null;
            }
            nOld = MallocSize(pOld);
            nNew = Global.Config.m.xRoundup(nBytes);
            if (nOld == nNew)
            {
                pNew = pOld;
            }
            else if (Global.Config.bMemstat)
            {
                MutexHelper.MutexEnter(Global.mem0.mutex);
                StatusHelper.StatusSet(SqliteStatus.SQLITE_STATUS_MALLOC_SIZE, nBytes);
                if (StatusHelper.StatusValue(SqliteStatus.SQLITE_STATUS_MEMORY_USED) + nNew - nOld >=
                    Global.mem0.alarmThreshold)
                {
                    MallocAlarm(nNew - nOld);
                }
                pNew = Global.Config.m.xRealloc(pOld, nNew);
                if (pNew == null && Global.mem0.alarmCallback != null)
                {
                    MallocAlarm(nBytes);
                    pNew = Global.Config.m.xRealloc(pOld, nNew);
                }
                if (pNew != null)
                {
                    nNew = MallocSize(pNew);
                    StatusHelper.StatusAdd(SqliteStatus.SQLITE_STATUS_MEMORY_USED, nNew - nOld);
                }
                MutexHelper.MutexLeave(Global.mem0.mutex);
            }
            else
            {
                pNew = Global.Config.m.xRealloc(pOld, nNew);
            }
            return pNew;
        }

        /*
    ** The public interface to sqlite3Realloc.  Make sure that the memory
    ** subsystem is initialized prior to invoking sqliteRealloc.
    */

        public static byte[] sqlite3_realloc(byte[] pOld, int n)
        {
#if !SQLITE_OMIT_AUTOINIT
            if (Sqlite3.sqlite3_initialize() != 0) return null;
#endif
            return sqlite3Realloc(pOld, n);
        }


        /*
    ** Allocate and zero memory.
    */

        public static byte[] MallocZero(int n)
        {
            byte[] p = sqlite3Malloc(n);
            if (p != null)
            {
                Array.Clear(p, 0, n); // memset(p, 0, n);
            }
            return p;
        }

        /*
    ** Allocate and zero memory.  If the allocation fails, make
    ** the mallocFailed flag in the connection pointer.
    */

        public static Mem DbMallocZero(sqlite3 db, Mem m)
        {
            return new Mem();
        }

        public static byte[] DbMallocZero(sqlite3 db, int n)
        {
            byte[] p = sqlite3DbMallocRaw(db, n);
            if (p != null)
            {
                Array.Clear(p, 0, n); // memset(p, 0, n);
            }
            return p;
        }

        /*
    ** Allocate and zero memory.  If the allocation fails, make
    ** the mallocFailed flag in the connection pointer.
    **
    ** If db!=0 and db->mallocFailed is true (indicating a prior malloc
    ** failure on the same database connection) then always return 0.
    ** Hence for a particular database connection, once malloc starts
    ** failing, it fails consistently until mallocFailed is reset.
    ** This is an important assumption.  There are many places in the
    ** code that do things like this:
    **
    **         int *a = (int*)sqlite3DbMallocRaw(db, 100);
    **         int *b = (int*)sqlite3DbMallocRaw(db, 200);
    **         if( b ) a[10] = 9;
    **
    ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed
    ** that all prior mallocs (ex: "a") worked too.
    */

        private static byte[] sqlite3DbMallocRaw(sqlite3 db, int n)
        {
            byte[] p;
            Debug.Assert(db == null || MutexHelper.MutexHeld(db.mutex));
#if !SQLITE_OMIT_LOOKASIDE
  if( db ){
    LookasideSlot *pBuf;
    if( db->mallocFailed ){
      return 0;
    }
    if( db->lookaside.bEnabled && n<=db->lookaside.sz
         && (pBuf = db->lookaside.pFree)!=0 ){
      db->lookaside.pFree = pBuf->pNext;
      db->lookaside.nOut++;
      if( db->lookaside.nOut>db->lookaside.mxOut ){
        db->lookaside.mxOut = db->lookaside.nOut;
      }
      return (void*)pBuf;
    }
  }
#else
            //if( db && db->mallocFailed ){
            //  return 0;
            //}
#endif
            p = sqlite3Malloc(n);
            //if( !p && db ){
            //  db->mallocFailed = 1;
            //}
            return p;
        }

        /*
    ** Resize the block of memory pointed to by p to n bytes. If the
    ** resize fails, set the mallocFailed flag in the connection object.
    */

        public static byte[] DbRealloc(sqlite3 db, byte[] p, int n)
        {
            byte[] pNew = null;
            Debug.Assert(db != null);
            Debug.Assert(MutexHelper.MutexHeld(db.mutex));
            //if( db->mallocFailed==0 ){
            if (p == null)
            {
                return sqlite3DbMallocRaw(db, n);
            }
#if !SQLITE_OMIT_LOOKASIDE
    if( isLookaside(db, p) ){
      if( n<=db->lookaside.sz ){
        return p;
      }
      pNew = sqlite3DbMallocRaw(db, n);
      if( pNew ){
        memcpy(pNew, p, db->lookaside.sz);
        MemPool.DbFree(db, ref p);
      }
    }else
#else
            {
                {
#endif
                    pNew = Malloc.sqlite3_realloc(p, n);
                    //if( !pNew ){
                    //  db->mallocFailed = 1;
                    //}
                }
            }
            return pNew;
        }

        /*
    ** Attempt to reallocate p.  If the reallocation fails, then free p
    ** and set the mallocFailed flag in the database connection.
    */

        public static byte[] DbReallocOrFree(sqlite3 db, byte[] p, int n)
        {
            byte[] pNew;
            pNew = DbRealloc(db, p, n);
            if (null == pNew)
            {
                MemPool.DbFree(db, ref p);
            }
            return pNew;
        }

        /*
    ** Make a copy of a string in memory obtained from sqliteMalloc(). These 
    ** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This
    ** is because when memory debugging is turned on, these two functions are 
    ** called via macros that record the current file and line number in the
    ** ThreadData structure.
    */
        //char *sqlite3DbStrDup(sqlite3 *db, const char *z){
        //  char *zNew;
        //  size_t n;
        //  if( z==0 ){
        //    return 0;
        //  }
        //  n = Utility.Sqlite3Strlen30(z) + 1;
        //  assert( (n&0x7fffffff)==n );
        //  zNew = sqlite3DbMallocRaw(db, (int)n);
        //  if( zNew ){
        //    memcpy(zNew, z, n);
        //  }
        //  return zNew;
        //}
        //char *sqlite3DbStrNDup(sqlite3 *db, const char *z, int n){
        //  char *zNew;
        //  if( z==0 ){
        //    return 0;
        //  }
        //  assert( (n&0x7fffffff)==n );
        //  zNew = sqlite3DbMallocRaw(db, n+1);
        //  if( zNew ){
        //    memcpy(zNew, z, n);
        //    zNew[n] = 0;
        //  }
        //  return zNew;
        //}



        /// <summary>
        ///  Create a string from the zFromat argument and the va_list that follows.
        ///  Store the string in memory obtained from sqliteMalloc() and make pz
        ///  point to that string.
        /// </summary>

        public static void SetString(ref string pz, sqlite3 db, string zFormat, params string[] ap)
        {
            //va_list ap;
            string z;

            Custom.VaStart(ap, zFormat);
            z = Print.VMPrintf(db, zFormat, ap);
            Custom.VaEnd(ap);
            MemPool.DbFree(db, ref pz);
            pz = z;
        }

        /*
    ** This function must be called before exiting any API function (i.e.
    ** returning control to the user) that has called sqlite3_malloc or
    ** Malloc.sqlite3_realloc.
    **
    ** The returned value is normally a copy of the second argument to this
    ** function. However, if a malloc() failure has occurred since the previous
    ** invocation StatusCode.SQLITE_NOMEM is returned instead.
    **
    ** If the first argument, db, is not NULL and a malloc() error has occurred,
    ** then the connection error-code (the value returned by sqlite3_errcode())
    ** is set to StatusCode.SQLITE_NOMEM.
    */

        public static int ApiExit(int zero, int rc)
        {
            sqlite3 db = null;
            return ApiExit(db, rc);
        }

        public static int ApiExit(sqlite3 db, int rc)
        {
            /* If the db handle is not NULL, then we must hold the connection handle
      ** mutex here. Otherwise the read (and possible write) of db.mallocFailed
      ** is unsafe, as is the call to Utility.Sqlite3Error().
      */
            Debug.Assert(db == null || MutexHelper.MutexHeld(db.mutex));
            if ( /*db != null && db.mallocFailed != 0 || */ rc == ExtendedResultCode.SQLITE_IOERR_NOMEM)
            {
                Utility.Sqlite3Error(db, StatusCode.SQLITE_NOMEM, "");
                //db.mallocFailed = 0;
                rc = StatusCode.SQLITE_NOMEM;
            }
            return rc & (db != null ? db.errMask : 0xff);
        }
    }
}